#include "clipboardmanager.h"
#include <QApplication>
#include <QRegularExpression>
#include <QJsonDocument>
#include <QJsonParseError>
#include <QJsonObject>
#include <QDateTime>
#include <QByteArray>
#include <QMimeData>
#include <QFile>
#include <QThread>
#include <QDebug>

constexpr int FILESIZELIMITMB = 8;

ClipboardManager::ClipboardManager(QObject *parent) :
    QObject(parent),
    m_pclipboard(QApplication::clipboard()),
    m_pbinbuf(new QByteArray),
    m_ptextbuf(new QByteArray),
    m_myHardwareId(QSysInfo::machineUniqueId())
{
    connect (m_pclipboard, &QClipboard::changed, this, &ClipboardManager::handleClipboard);
}

QByteArray ClipboardManager::data() const
{
    return QByteArray::fromBase64(*m_ptextbuf);
}

void ClipboardManager::clear()
{
    emit clearFields();
    m_ptextbuf->clear();
    m_pbinbuf->clear();
    m_fileName.clear();
}

void ClipboardManager::handleClipboard()
{
    QString text = m_pclipboard->mimeData()->text();

    // Попытка чтения локального файла
    QString path = QByteArray::fromPercentEncoding(text.toUtf8());
    path.remove(QRegularExpression("^file://"));
    path.remove("\r\n");
#ifdef WIN32
    path.remove(QRegularExpression("^/"));
#endif

    QFile file(path);
    if (file.exists())
    {
        clear();
        if (not file.open(QIODevice::ReadOnly))
        {
            emit clearFields();
            return;
        }
        int sizeMb = file.size() / 1024 / 1024;
        if (FILESIZELIMITMB < sizeMb)
        {
            emit tooBigSize(QString("Size limit is %1 MB, selected file is %2 MB").arg(FILESIZELIMITMB).arg(sizeMb));
            file.close();
            return;
        }
        m_fileName = path;
        m_fileName.remove(QRegularExpression("^.*/"));
        *m_pbinbuf = file.read(FILESIZELIMITMB*1024*1024);
        file.close();
        rawBufferChanged(m_fileName);
        return;
    }

    // На Debian буфер больше ~0.5МБ обнуляется (последовательно фрагментируется)
    // Накапливаем во внутренний буфер, если информация поступает за <500 ms.
    if (QDateTime::currentMSecsSinceEpoch() - m_lastBufferChanging < 500)
    {
        if (not text.isEmpty())
        {
            *m_ptextbuf += text.toUtf8();
        }
    }else{
        clear();
        *m_ptextbuf = text.toUtf8();
    }

    // Возможно, JSON => Получение
    QJsonParseError jErr;
    QJsonDocument::fromJson(*m_ptextbuf, &jErr);
    if (jErr.error == QJsonParseError::NoError)
    {
        QJsonObject obj = QJsonDocument::fromJson(text.toUtf8()).object();
        bool status = obj.value("clipboardTransferBase64String").toBool();
        QString name = obj.value("fileName").toString();
        QString data = obj.value("data").toString();

        if (status and !name.isEmpty() and !data.isEmpty())
        {
            if (obj.value("hardwareId").toString() == m_myHardwareId)
            {
                m_ptextbuf->clear();
                emit preparedToTransfer(name);
                return;
            }
            m_lastBufferChanging = m_lastBufferChanging-501;
            *m_ptextbuf = data.toUtf8();
            emit readyToSave(name);
        }
    }

    m_lastBufferChanging = QDateTime::currentMSecsSinceEpoch();

}

void ClipboardManager::prepareToTransfer()
{
    QJsonObject obj;
    obj.insert("clipboardTransferBase64String", true);
    obj.insert("fileName", m_fileName);
    obj.insert("hardwareId", m_myHardwareId);
    obj.insert("data", QString(m_pbinbuf->toBase64()));
    QByteArray array = QJsonDocument(obj).toJson(QJsonDocument::JsonFormat::Compact);
    m_pclipboard->setText(array);
//    int pos = 0;
//    int arraySize = array.size();
//    while (pos < arraySize)
//    {
//        qInfo() << "INSERTING";
//        QByteArray tmpArr (array);
//        tmpArr.remove(0, pos);

//        int partSize = 528288; // 0,5 MiB
//        int tail = arraySize - pos;
//        if (tail < partSize) partSize = tail;

//        pos += partSize;
//        m_pclipboard->setText(tmpArr.left(partSize));
////        QThread::msleep(10);
//    }
}
